﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
#if XNA
using Microsoft.Xna.Framework;
#else
using SilverArcade.SilverSprite;
#endif
namespace CakeAnimation
{
    public class KeyFrame
    {
        public float Time;
        public Skeleton Pose;

        public KeyFrame(AnimationContext context, float time, Skeleton skeletonTemplate)
        {
            Time = time;
            Pose = skeletonTemplate.Clone();
        }
    }

    public class KeyFrameController
    {
        public void Update(Skeleton skeleton, KeyFrame kf1, KeyFrame kf2, float time)
        {
            time -= kf1.Time;
            time /= (kf2.Time - kf1.Time);

            InterplateSkeleton(skeleton, kf1.Pose, kf2.Pose, time);
        }

        public void InterplateSkeleton(Skeleton target, Skeleton sk1, Skeleton sk2, float time)
        {
            InterpolateBone(target.RootBone, sk1.RootBone, sk2.RootBone, time);
            target.RootBone.UpdateTransform();
        }

        public void InterpolateBone(Bone targetBone, Bone bone1, Bone bone2, float time)
        {
            targetBone.LocalPosition = Vector2.Lerp(bone1.LocalPosition, bone2.LocalPosition, time);
            targetBone.LocalRotation = LerpAngle(bone1.LocalRotation, bone2.LocalRotation, time);

            for (int i = 0; i < targetBone.Children.Count; ++i)
            {
                InterpolateBone(
                    targetBone.Children[i],
                    bone1.Children[i],
                    bone2.Children[i],
                    time);
            }
        }

        public static float WrapAngle(float angle)
        {
#if XNA
            return MathHelper.WrapAngle(angle);
#else
            while (angle < -MathHelper.TwoPi)
                angle += MathHelper.TwoPi;
            while (angle > Math.PI)
                angle -= MathHelper.TwoPi;
            
            return angle;
#endif
        }


        public static float LerpAngle(float start, float end, float scale)
        {
            start = WrapAngle(start);
            end = WrapAngle(end);
            float delta = end - start;

            // If delta is not the shortest way, travel in the opposite direction  
            if (delta > MathHelper.Pi)
            {
                return (WrapAngle(start - (MathHelper.TwoPi - delta) * scale));
            }
            else if (delta < -MathHelper.Pi)
            {
                return (WrapAngle(start + (MathHelper.TwoPi + delta) * scale));
            }

            // No special case needed  
            return (start + delta * scale);
        }
    }
}
